﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace FourKill.Engine
{

    public abstract class BaseSpriteSheet : ISpriteSheet
    {
        private int _height, _width;
        private Color _transparentColor;
        private Bitmap[][] _images;
        private Bitmap[][] _masks;

        //private int _bottomClip = 0;

        public BaseSpriteSheet(Bitmap sheetImage, int columns, int rows)
        {
            this._height = (sheetImage.Height / rows)-BottomClip;
            this._width = sheetImage.Width / columns;

            this.DetermineTransparentColor(sheetImage);

            //_masks = SplitSheet(Utility.CreateMask(sheetImage, _transparentColor), columns, rows, BottomClip);
            _images = SplitSheet(sheetImage, columns, rows, BottomClip);
            Utility.CreateMask(sheetImage, _transparentColor);
        }

        public BaseSpriteSheet(Bitmap sheetImage, int columns, int rows, Color transparentColor)
        {
            this._height = sheetImage.Height / rows;
            this._width = sheetImage.Width / columns;
            this._transparentColor = transparentColor;
            //_masks = SplitSheet(Utility.CreateMask(sheetImage, transparentColor), columns, rows, BottomClip);
            _images = SplitSheet(sheetImage, columns, rows, BottomClip);
        }

        public virtual int BottomClip
        {
            get { return 0; }
        }
        
        public int Height
        {
            get { return _height; }
            set { _height = value; }
        }

        public int Width
        {
            get { return _width; }
            set { _width = value; }
        }

        public double HeightToWidthRatio
        {
            get { return (double)_height / (double)_width; }
        }

        public Color TransparentColor
        {
            get { return _transparentColor; }
            set { _transparentColor = value; }
        }        

        public Bitmap this[int x, int y]
        {
            get
            {
                return this._images[y][x];
            }
        }

        public abstract int GetFrameCount(SpriteState state);
        public abstract Bitmap GetImage(double angle, int index, SpriteState state);

        public virtual Bitmap GetScaledImage(double angle, int index, SpriteState state, int? width, int? height)
        {
            var image = GetImage(angle, index, state);
            int newWidth = 0, newHeight = 0;

            if (width.HasValue) newWidth = width.Value;
            if (height.HasValue) newHeight = height.Value;

            if (!height.HasValue && width.HasValue) newHeight = newWidth * (Height / Width); // x/12 = 8/4, x = 8/4*12 
            else if (height.HasValue && !width.HasValue) newWidth = newHeight * (Width / Height); // x/12 = 8/4, x = 8/4*12 
            
            return Utility.ResizeImage(newWidth, newHeight, image);
        }

        protected enum SpriteDirection
        {
            Right,
            RightBack,
            Back,
            LeftBack,
            Left,
            LeftFront,
            Front,
            RightFront
        }
        
        protected virtual SpriteDirection Determine4WayDirection(double angle)
        {
            var a = angle > Utility._360 ? (angle % Utility._360) : angle;

            if ((a >= 0 && a < Math.PI / 4) || (a >= Utility._315 && a <= (Math.PI * 2))) 
                return SpriteDirection.Back;
            else if (a >= Utility._45 && a < Utility._135)
                return SpriteDirection.Left;
            else if (a >= Utility._135 && a < Utility._225)
                return SpriteDirection.Front;
            else
                return SpriteDirection.Right;
        }

        protected virtual SpriteDirection Determine8WayDirection(double angle)
        {
            var a = angle > Utility._360 ? (angle % Utility._360) : angle;

            if ((a >= 0 && a < Utility.Radians(22.5)) || (a >= Utility.Radians(337.5) && a <= Utility._360))
                return SpriteDirection.Back;
            else if (a >= Utility.Radians(22.5) && a < Utility.Radians(67.5))
                return SpriteDirection.LeftBack;
            else if (a >= Utility.Radians(67.5) && a < Utility.Radians(112.5))
                return SpriteDirection.Left;
            else if (a >= Utility.Radians(112.5) && a < Utility.Radians(157.5))
                return SpriteDirection.LeftFront;
            else if (a >= Utility.Radians(157.5) && a < Utility.Radians(202.5))
                return SpriteDirection.Front;
            else if (a >= Utility.Radians(202.5) && a < Utility.Radians(247.5))
                return SpriteDirection.RightFront;
            else if (a >= Utility.Radians(247.5) && a < Utility.Radians(292.5))
                return SpriteDirection.Right;
            else
                return SpriteDirection.RightBack;
        }

        protected virtual void DetermineTransparentColor(Bitmap image)
        {
            Dictionary<Color, int> colorCounts = new Dictionary<Color, int>();
            Color argb;
            for (int x = 0; x < Width; x++)
            {
                argb = image.GetPixel(x, 0);
                if (colorCounts.ContainsKey(argb)) colorCounts[argb]++;
                else colorCounts[argb] = 1;

                argb = image.GetPixel(x, Height - 1);
                if (colorCounts.ContainsKey(argb)) colorCounts[argb]++;
                else colorCounts[argb] = 1;
            }
            for (int y = 1; y < Width-2; y++)
            {
                argb = image.GetPixel(0, y);
                if (colorCounts.ContainsKey(argb)) colorCounts[argb]++;
                else colorCounts[argb] = 1;

                argb = image.GetPixel(Width-1, y);
                if (colorCounts.ContainsKey(argb)) colorCounts[argb]++;
                else colorCounts[argb] = 1;
            }
            
            this._transparentColor = colorCounts.OrderByDescending(kv => kv.Value).First().Key;
        }

        protected virtual Bitmap[][] SplitSheet(Bitmap sheetImage, int columns, int rows, int bottomClip)
        {
            var images = new Bitmap[rows][];
            for (int y = 0; y < rows; y++)
            {
                images[y] = new Bitmap[columns];
                for (int x = 0; x < columns; x++)
                {
                    images[y][x] = sheetImage.Clone(new Rectangle(x * Width, y * (Height + bottomClip), Width, Height), sheetImage.PixelFormat);
                    images[y][x].MakeTransparent(TransparentColor);
                }
            }
            return images;
        }
    }
}
